import logging, logging.handlers, os, inspect, sys, re, types, ast, Queue, time, gc, functools, traceback

from datetime import datetime
from multiprocessing import Process, Event, JoinableQueue

from settings import settings

STOP = r"-/<({[|STOP|]}}>\-"

Q = JoinableQueue()

class QueueHandler(logging.Handler):
	"""
	Handler that puts all log entries into a multiprocessing Queue.
	"""
	def __init__(self, queue):
		logging.Handler.__init__(self)
		self.queue = queue

	def emit(self, record):
		try:
			self.queue.put(record)
		except:
			_err_log.handle(record)
			sys.exit(1)


_err_log = logging.getLogger("Error Logger")

_err_log.addHandler(logging.StreamHandler())

if not os.path.exists(settings.path.log):
	os.mkdir(settings.path.log)
        
def _safe_str(obj):
	""" return the byte string representation of obj """
	try:
		return str(obj)
	except UnicodeEncodeError:
		# obj is unicode
		try:
			return str(obj.encode("utf-8"))
		except UnicodeEncodeError:
			unicode_text = unicode(obj).encode("unicode_escape")
			return str(unicode_text)


def _safe_unicode(obj, *args):
	""" return the unicode representation of obj """
	try:
		return unicode(obj, *args)

	except UnicodeDecodeError:
		# obj is byte string
		try:
			return unicode(obj.decode("utf-8"))
		except UnicodeDecodeError:
			ascii_text = str(obj).encode('string_escape')
			return unicode(ascii_text)


def initLog(name):
	"""
	Initializes a logger to use for logging within the application.
	"""

	log = logging.getLogger(name)
		
	_err_log.info("Initializing log: {logname}".format(logname = name))

	nolog = False
	debug = False

	if hasattr(settings.log.type, name):
		logsettings = getattr(settings.log.type, name)

		if hasattr(logsettings, "debug"):
			debug = getattr(logsettings, "debug")

		if hasattr(logsettings, "nolog"):
			nolog = getattr(logsettings, "nolog")

	if nolog:
		level = logging.ERROR

	elif debug:
		level = logging.DEBUG

	else:
		level = logging.INFO


	handler = QueueHandler(Q)
		
	log.addHandler(handler)

	log.setLevel(level)

	return log

_log = initLog("xdh_logging")

def sublogName(obj):
	module = inspect.getmodule(obj)
	if hasattr(module, "__file__"):
		module_name = settings.re.pymodfile.search(os.path.basename(inspect.getmodule(obj).__file__)).group(1)

	else:
		module_name = module.__name__

	logname = "{module}_{func}".format(module = module_name, func = obj.__name__)

	return logname


class LoggerProcess(Process):

	def __init__(self, filename):
		super(LoggerProcess, self).__init__()
		Process.__init__(self)
		self.filename = filename

		self.make_logger()

		self.start()


	def make_logger(self):
		self.log = logging.getLogger()
		
		handler = logging.handlers.TimedRotatingFileHandler(
			self.filename,
			when = settings.log.when,
			interval = settings.log.interval,
			encoding = settings.log.encoding,
			backupCount = settings.log.backup_count
		)

		formatter = logging.Formatter(settings.log.format_string, )
		handler.setFormatter(formatter)
        
		for handler in list(self.log.handlers):
			self.log.removeHandler(handler)

		self.log.addHandler(handler)

		self.prev_record = None



	def run(self):
		try:
			_log.info("Starting Log Writing loop.")

			while True:
#				self.make_logger()
				item = Q.get()
				Q.task_done()
				if item == STOP:
					_log.debug("Got stop from {name} Queue.".format(name = LoggerProcess.__name__))
					break

			_log.info("Ending Log Writing loop.")
		except Exception, e:
			_err_log.error("{name}: {msg}".format(name = e.__class__.__name__, msg = e))
			_err_log.error("".join(traceback.format_exception(*sys.exc_info())))


class LogWriter(object):
	running = False

	def __init__(self, filename = os.path.join(settings.path.log, settings.log.filename)):
		self.filename = filename


	def __enter__(self):
		if not LogWriter.running:
			_log.info("Logging started.")
			LogWriter.running = True

			self.process = LoggerProcess(self.filename)

		return self


	def __exit__(self, type, value, tback):
		if LogWriter.running:
			_log.info("Logging Finished.")
			Q.put(STOP)

			Q.join()
        
			Q.close()
        
			self.process.join()

			del self.process

			if type != None:

				_err_log.error("{name}: {msg}".format(name = value.__class__.__name__, msg = value))
				_err_log.error("".join(traceback.format_exception(*sys.exc_info())))
        
			LogWriter.running = False

if __name__ == "__main__":
	print sublogName(LogWriter)
